 //-----------------------------------------------------------------------------
//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   RASTER
//File Name     :   clz_96.v
//Module name   :   clz_96
//Full name     :   96 bit unsigned numbei leading zero count
//
//Author        :   zha daolu
//Email         :   
//Data          :   2020/5/13
//Version       :   V1.00
//
//Abstract      :   
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//
//-----------------------------------------------------------------------------    
module clz_96(
    clk,
    rst_n,
    busy,
    Data_en,
    Data_in,
    LZB_out,
    LZB_valid
);
input clk;
input rst_n;
input busy;
input Data_en;
input   [95:0]  Data_in;
output reg [ 6:0]  LZB_out;
output LZB_valid;

reg clz_64_en;
reg clz_96_en;
reg [95:0] Data_in_ff1;

always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
        Data_in_ff1 <= 96'b0;
    else if(~busy && Data_en)
        Data_in_ff1 <= Data_in;
end

always@(posedge clk or negedge rst_n)
begin
   if(~rst_n)
       clz_64_en <= 1'b0;
   else if(~busy)
   begin
      if(Data_en && Data_in[95:64] == 32'b0)
          clz_64_en <= 1'b1;
      else
          clz_64_en <= 1'b0;
   end
end

always@(posedge clk or negedge rst_n)
begin
   if(~rst_n)
       clz_96_en <= 1'b0;
   else if(~busy)
   begin
      if(Data_en && Data_in[95:64] != 32'b0)
          clz_96_en <= 1'b1;
      else
          clz_96_en <= 1'b0;
   end
end 

reg [6:0] LZB_96;
wire [6:0] LZB_64;

always@(*)
begin
  case(Data_in_ff1[95:64])
      32'b1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'b0;
      32'b01xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'b1;
      32'b001xxxxxxxxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd2;
      32'b0001xxxxxxxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd3;
      32'b00001xxxxxxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd4;
      32'b000001xxxxxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd5;
      32'b0000001xxxxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd6;
      32'b00000001xxxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd7;
      32'b000000001xxxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd8;
      32'b0000000001xxxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd9;
      32'b00000000001xxxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd10;
      32'b000000000001xxxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd11;
      32'b0000000000001xxxxxxxxxxxxxxxxxxx: LZB_96 = 7'd12;
      32'b00000000000001xxxxxxxxxxxxxxxxxx: LZB_96 = 7'd13;
      32'b000000000000001xxxxxxxxxxxxxxxxx: LZB_96 = 7'd14;
      32'b0000000000000001xxxxxxxxxxxxxxxx: LZB_96 = 7'd15;
      32'b00000000000000001xxxxxxxxxxxxxxx: LZB_96 = 7'd16;
      32'b000000000000000001xxxxxxxxxxxxxx: LZB_96 = 7'd17;
      32'b0000000000000000001xxxxxxxxxxxxx: LZB_96 = 7'd18;
      32'b00000000000000000001xxxxxxxxxxxx: LZB_96 = 7'd19;
      32'b000000000000000000001xxxxxxxxxxx: LZB_96 = 7'd20;
      32'b0000000000000000000001xxxxxxxxxx: LZB_96 = 7'd21;
      32'b00000000000000000000001xxxxxxxxx: LZB_96 = 7'd22;
      32'b000000000000000000000001xxxxxxxx: LZB_96 = 7'd23;
      32'b0000000000000000000000001xxxxxxx: LZB_96 = 7'd24;
      32'b00000000000000000000000001xxxxxx: LZB_96 = 7'd25;
      32'b000000000000000000000000001xxxxx: LZB_96 = 7'd26;
      32'b0000000000000000000000000001xxxx: LZB_96 = 7'd27;
      32'b00000000000000000000000000001xxx: LZB_96 = 7'd28;
      32'b000000000000000000000000000001xx: LZB_96 = 7'd29; 
      32'b0000000000000000000000000000001x: LZB_96 = 7'd30;
      32'b00000000000000000000000000000001: LZB_96 = 7'd31;     
      default: LZB_96 = 7'b0;
  endcase                                                                                                                
end

clz_64 u_clz_64(
    .Data_in(Data_in_ff1[63:0]),
    .LZB_out(LZB_64) 
);

always@(posedge clk or negedge rst_n)
begin
   if(~rst_n)
       LZB_out <= 7'b0;
   else if(~busy)
   begin
      if(clz_96_en)
          LZB_out <= LZB_96;
      else if(clz_64_en)
          LZB_out <= LZB_64 + 6'd32;
   end
end

reg valid_reg;

always@(posedge clk or negedge rst_n)
begin
   if(~rst_n)
       valid_reg <= 1'b0;
   else if(~busy)
   begin
      if(clz_96_en || clz_64_en)
          valid_reg <= 1'b1;
      else
          valid_reg <= 1'b0;
   end
end

assign LZB_valid = valid_reg && ~busy;
                                                                                                                         
endmodule
